package com.jandar.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.Arrays;

import com.jandar.Resources;

/**
 * JDBC工具类。
 * 
 * @author pqj
 * @version 2009-6-2
 */
public class DBUtils {

	private static DBUtils instance = new DBUtils();;

	private String driver = null;
	private String url = null;
	private boolean initFlag = false;

	private DBUtils() {
		try {
			Resources config = Resources.getInstance();
			driver = config.getDriver();
			url = config.getUrl();

			Class.forName(driver);
			initFlag = true;
		} catch (Exception e) {
			ExceptionUtils.error(e);
			initFlag = false;
		}
	}

	public static DBUtils getInstance() {
		return instance;
	}

	public static void closeConnection(Connection conn) throws SQLException {
		if (conn != null) {
			conn.close();
		}
	}

	public static void closeStatement(Statement statement) throws SQLException {
		if (statement != null) {
			statement.close();
		}
	}

	public static void closeResultSet(ResultSet resultSet) throws SQLException {
		if (resultSet != null) {
			resultSet.close();
		}
	}

	public Connection getConnection() throws SQLException {
		if (initFlag) {
			return DriverManager.getConnection(url);
		} else {
			return null;
		}
	}

	public PreparedStatement getPreparedStatement(Connection conn, String sql)
			throws SQLException {
		PreparedStatement preparedStatement = conn.prepareStatement(sql);
		return preparedStatement;
	}

	public ResultSet ExecuteQuery(PreparedStatement preparedStatement,
			String sql, Object[] params) throws SQLException {
		ResultSet resultSet = null;
		try {
			this.fillStatement(preparedStatement, params);
			resultSet = preparedStatement.executeQuery();
		} catch (SQLException e) {
			this.rethrow(e, sql, params);
		}
		return resultSet;
	}

	public int ExecuteUpdate(Connection connection, String sql, Object[] params)
			throws SQLException {

		int rows = 0;
		PreparedStatement preparedStatement = null;
		try {
			preparedStatement = this.getPreparedStatement(connection, sql);
			this.fillStatement(preparedStatement, params);
			rows = preparedStatement.executeUpdate();
		} catch (SQLException e) {
			this.rethrow(e, sql, params);
		} finally {
			DBUtils.closeStatement(preparedStatement);
		}
		return rows;
	}

	public int ExecuteUpdate(String sql, Object[] params) throws SQLException {

		int rows = 0;
		PreparedStatement preparedStatement = null;
		Connection conn = null;
		try {
			conn = this.getConnection();
			preparedStatement = this.getPreparedStatement(conn, sql);
			this.fillStatement(preparedStatement, params);
			rows = preparedStatement.executeUpdate();
		} catch (SQLException e) {
			this.rethrow(e, sql, params);
		} finally {
			DBUtils.closeStatement(preparedStatement);
			DBUtils.closeConnection(conn);
		}
		return rows;
	}

	private void fillStatement(PreparedStatement stmt, Object[] params)
			throws SQLException {

		if (params == null) {
			return;
		}

		for (int i = 0; i < params.length; ++i) {
			if (params[i] != null) {
				stmt.setObject(i + 1, params[i]);
			} else {
				stmt.setNull(i + 1, Types.CHAR);
			}
		}
	}

	private void rethrow(SQLException cause, String sql, Object params[])
			throws SQLException {

		StringBuilder msg = new StringBuilder();
		msg.append(" Query :");
		msg.append(sql);
		if (params == null) {
			msg.append("[]");
		} else {
			msg.append(Arrays.asList(params));
		}
		SQLException exception = new SQLException(msg.toString(), cause
				.getSQLState(), cause.getErrorCode());
		exception.setNextException(cause);

		throw exception;
	}
}
